package com.tyc.shiro.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.code.kaptcha.Producer;
import com.tyc.shiro.entity.SysCaptcha;
import com.tyc.shiro.entity.SysUser;
import com.tyc.shiro.form.SysLoginForm;
import com.tyc.shiro.oauth2.TokenGenerator;
import com.tyc.shiro.util.SaltGenerator;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 类描述
 *
 * @author tyc
 * @version 1.0
 * @date 2023-12-22 09:53:35
 */
@RestController
@RequestMapping("sys")
public class SysController {
    @Autowired
    private Producer producer;

    private Map<String, SysCaptcha> codeMap = new ConcurrentHashMap<>();

    /**
     * 生成图形验证码
     * 测试：
     *      在线网站：https://www.uutils.com/image/base64_to_image.htm
     *      将字符串 data:image/png;base64, 与 base64 编码结果填入输入框
     *
     * data:image/png;base64,
     * @param response
     */
    @GetMapping("captcha")
    public JSONObject captcha(HttpServletResponse response){
        JSONObject jsonObject = new JSONObject();
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/png");
        String uuid = UUID.randomUUID().toString().replace("-","");
        // 生成验证码
        String code = producer.createText();
        // 生成图片
        BufferedImage image = producer.createImage(code);
        // todo 将uuid对应的code 存储到数据库并添加过期时间 定时清除数据库中的验证码
        Date expireTime = new Date(System.currentTimeMillis() + 1000 * 60 * 5);
        SysCaptcha sysCaptcha = new SysCaptcha(uuid, code, expireTime);
        codeMap.put(uuid,sysCaptcha);
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try {
            // 写入流 base64 编码后返回
            ImageIO.write(image, "png", os);
            //将图片输出给浏览器
//            ImageIO.write(image, "png", response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            jsonObject = jsonObject.set("code", 500);
        }
        jsonObject.set("uuid",uuid);
        jsonObject.set("img", Base64.encode(os.toByteArray()));
        System.out.println("data:image/png;base64,"+Base64.encode(os.toByteArray()));
        return jsonObject;
    }



    @PostMapping("/login")
    public String login(@RequestBody @Valid SysLoginForm sysLoginForm){
        // 校验验证码
        String uuid = sysLoginForm.getUuid();
        // 验证码只能使用一次
        SysCaptcha sysCaptcha = codeMap.remove(uuid);
        if(sysCaptcha == null || !sysLoginForm.getCode().equals(sysCaptcha.getCode())){
            return "验证码错误";
        }
        if (sysCaptcha.getExpireTime().getTime() < System.currentTimeMillis()) {
            return "验证码过期";
        }
        String username = sysLoginForm.getUsername();
        // todo 从数据库获取用户信息
        SysUser sysUser = getSysUser(username);
        // 判断非空比对密码
        // todo sysLoginForm 中密码应为：RSA(MD5(原密码))
        if(sysUser == null || !sysUser.getPassword().equals(new Sha256Hash(sysLoginForm.getPassword(),sysUser.getSalt()).toHex())){
            return "账号或密码错误";
        }
        if(sysUser.getStatus() == 0){
            return "账号不可用，请联系管理员";
        }
        // 生成 token 并返回
        String token = TokenGenerator.generateValue();
        // 设置 token 生成过期时间
        Long expireTime = System.currentTimeMillis() + 1000 * 3600 * 12;
        // todo 查询数据库中是否存在用户对应的 token，有则更新，无则新增
        // 设置 token 对应的用户 id
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("token",token);
        jsonObject.set("expireTime", expireTime);
        return JSONUtil.toJsonStr(jsonObject);
    }

    /**
     * 测试认证
     */
    @GetMapping("/common")
    public String common(){
        SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
        return JSONUtil.toJsonStr(sysUser);
    }

    /**
     * 授权
     */
    @RequiresRoles(value = {"admin","aaaa"},logical = Logical.OR) // 拥有某个角色即可访问
    @RequiresPermissions(value = {"secure:add","secure:edit"},logical = Logical.AND) // 拥有所有权限才能访问
    @GetMapping("/secure")
    public String test(){
        return "SUCCESS";
    }

    public static SysUser getSysUser(String username){
        if(!"admin".equals(username)){
            return null;
        }
        SysUser sysUser = new SysUser();
        sysUser.setId(1L);
        sysUser.setUsername(username);
        sysUser.setStatus(1);
        sysUser.setCreateTime(new Date());
        String salt = SaltGenerator.generateSalt();
        sysUser.setSalt(salt);
        String password = new Sha256Hash("123456",sysUser.getSalt()).toHex();
        sysUser.setPassword(password);
        return sysUser;
    }
}
